﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Xml;
using SHomeWorkshop.LunarPresentation.Interfaces;

namespace SHomeWorkshop.LunarPresentation.Expressions
{
    public class SubPanel : StackPanelExpression, IDirection
    {
        /// <summary>
        /// 构造子面板实例。
        /// </summary>
        /// <param name="rootPanel">根面板。</param>
        /// <param name="parentPanel">父面板。注意：子面板通常不能独立存在。
        /// 除根面板独立存在之外，其它情况下总是嵌入其它公式中，因此此处应总是传入null。</param>
        /// <param name="editor">所在编辑器</param>
        /// <param name="parentExpression">所在公式。作根面板时为null。</param>
        public SubPanel(SubPanel rootPanel, SubPanel parentPanel,
            Editor editor, Expression parentExpression)
            : base(rootPanel, parentPanel, editor)
        {
            this.MaxWidth = double.MaxValue;//导出公式图前会检查这个值。
            this.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
            this.parentExpression = parentExpression;

            this.chineseName = "子面板";
            //this.selectAdorner.IsSubPanel = true;

            // 阻止子面板被拖动。
            this.SelectAdorner.Cursor = System.Windows.Input.Cursors.Arrow;
            this.SelectAdorner.MouseLeftButtonDown +=
                new System.Windows.Input.MouseButtonEventHandler(selectAdorner_MouseLeftButtonDown);

            //重绘树型线。
            this.mainBorder.SizeChanged += new SizeChangedEventHandler(mainBorder_SizeChanged);
        }

        void mainBorder_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            RefreshTreeLinesOfHeaderText();
        }

        //子面板不应支持此事件，故为null。
        void selectAdorner_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Globals.dragSourceExpression = null;
        }

        public override string ChineseName
        {
            get
            {
                if (this.RootPanel != null && this.RootPanel != this)
                {
                    return chineseName;
                }
                else
                {
                    return "根面板";
                }
            }
        }

        private Orientation direction = Orientation.Vertical;

        public Orientation Direction
        {
            get { return direction; }
            set
            {
                if (direction == value) return;

                direction = value;

                if (this.basePanel != null)
                {
                    this.basePanel.Orientation = value;
                }

                if (this.XmlData != null)
                {
                    this.XmlData.SetAttribute("Direction", value.ToString());
                }

                OnPropertyChanged(this, new PropertyChangedEventArgs("Direction"));

                // 更新所有公式的对齐方式。
                foreach (UIElement ue in basePanel.Children)
                {
                    Expressions.Expression ex = ue as Expressions.Expression;

                    if (ex != null)
                    {
                        ex.UpdateAlignment();
                        ex.IndentAdorner.InvalidateVisual();
                    }
                }

                Editor.IsModified = true;
            }
        }

        public override Brush ExForeground
        {
            get
            {
                return base.ExForeground;
            }
            set
            {
                UpdateExForegroundWithoutXmlChanging(value);
                UpdateExForegroundToXmlData(value);
                Editor.IsModified = true;
            }
        }

        public override void UpdateExForegroundWithoutXmlChanging(Brush value)
        {
            base.UpdateExForegroundWithoutXmlChanging(value);

            base.exForeground = value;
        }

        public Expressions.Expression LastChildEx
        {
            get
            {
                if (this.basePanel == null) return null;

                if (this.basePanel.Children.Count >= 1)
                {
                    return this.basePanel.Children[this.basePanel.Children.Count - 1] as Expressions.Expression;
                }

                return null;
            }
        }

        public Expressions.Expression LastVisibleChildEx
        {
            get
            {
                if (this.basePanel == null) return null;

                for (int i = this.basePanel.Children.Count - 1; i >= 0; i--)
                {
                    Expressions.Expression e = this.basePanel.Children[i] as Expressions.Expression;
                    if (e != null && e.Visibility == Visibility.Visible)
                    {
                        return e;
                    }
                }

                return null;
            }
        }

        protected override void BuildChildren()
        {
            base.BuildChildren();

            basePanel.Children.Clear();

            if (this.XmlData == null) return;
            XmlAttribute attrDirection = this.XmlData.GetAttribute("Direction");
            if (attrDirection != null)
            {
                this.direction = (attrDirection.Value == "Horizontal")
                    ? Orientation.Horizontal : Orientation.Vertical;
                if (this.basePanel != null)
                {
                    this.basePanel.Orientation = this.direction;
                }
            }

            //读取当前编辑器全局字体。
            if (this.RootPanel == null || this.RootPanel == this)
            {
                XmlAttribute exFontSize = this.XmlData.GetAttribute("ExFontSize");
                if (exFontSize != null)
                {
                    int fontSize = int.Parse(exFontSize.Value);
                    TextElement.SetFontSize(this, fontSize);
                    this.Editor.SetExFontSizeWithoutEvents(fontSize);
                }
            }

            XmlAttribute attrSkipSelect = this.XmlData.GetAttribute("SkipSelect");
            if (attrSkipSelect != null && attrSkipSelect.Value.ToLower() == "true")
            {
                this.skipSelect = true;
            }

            XmlAttribute attrTrySemiAutoNum = this.XmlData.GetAttribute("TrySemiAutoNum");
            if (attrTrySemiAutoNum != null && attrTrySemiAutoNum.Value.ToLower() == "true")
            {
                this.trySemiAutoNum = true;
            }

            XmlNodeList xmlNodes = XmlData.SelectNodes("Expression");

            SubPanel rootPanel = this.RootPanel;
            if (rootPanel == null)
            {
                rootPanel = this;/*如果当前子面板的根面板为空，说明当前子面板就是根面板*/
            }
            // 如果此处不作处理，在打开文件并自动生成各公式时就会出问题——所有公式的RootPanel都是null。

            foreach (XmlNode node in xmlNodes)
            {
                if (node.Name == "Expression")
                {
                    Expression ex = BuildExpression(node, rootPanel, this, this.Editor);
                    this.basePanel.Children.Add(ex);
                }
            }

            // 刷新所有子公式的对齐位置。
            foreach (UIElement ue in basePanel.Children)
            {
                Expression ex = ue as Expressions.Expression;

                if (ex != null)
                {
                    ex.UpdateAlignment();
                }
            }

            RefreshAutoNumbersOfBaseText();
            RefreshHeaderTextCollapsed();
        }

        public void RefreshHeaderTextCollapsed()
        {
            //此处必须逆序调用。否则下级标题的状态会覆盖上级标题的折叠状态。
            //而设计时，上级标题是应该具备控制下级标题及其更下级公式状态的。
            for (int i = this.basePanel.Children.Count - 1; i >= 0; i--)
            {
                Expressions.Expression ex = this.basePanel.Children[i] as Expressions.Expression;
                if (ex is Expressions.BaseText)
                {
                    Expressions.BaseText bt = ex as Expressions.BaseText;
                    bt.RefreshIsCollapsed();
                }
            }
        }

        private Expression parentExpression;

        public Expression ParentExpression
        {
            get { return parentExpression; }
            set { parentExpression = value; }
        }

        public Expressions.Grid ParentGrid
        {
            get { return parentExpression as Expressions.Grid; }
        }

        #region 这四个属性用以导航，不能是只读属性！！！
        public virtual SubPanel LeftSubPanel { get; set; }

        public virtual SubPanel RightSubPanel { get; set; }

        public virtual SubPanel TopSubPanel { get; set; }

        public virtual SubPanel BottomSubPanel { get; set; }
        #endregion

        private bool skipSelect = false;

        /// <summary>
        /// 这个属性最初是用在“行”中唯一的子面板中。
        /// 此属性值只能从Xml属性中（由Build方法）读取。
        /// </summary>
        public bool SkipSelect
        {
            get { return skipSelect; }
        }

        private bool trySemiAutoNum = false;

        /// <summary>
        /// 半自动编号。子面板中出现任何一个非零级缩进的文本块或出现任何一个标题文本块，
        /// 都会导致“半自动编号”失效。
        /// </summary>
        public bool TrySemiAutoNum
        {
            get { return trySemiAutoNum; }
            set
            {
                trySemiAutoNum = value;
                this.XmlData.SetAttribute("TrySemiAutoNum", value.ToString());
                RefreshAutoNumbersOfBaseText();
            }
        }

        /// <summary>
        /// 任何一个非零级缩进的文本块、
        /// 或任何一个标题文本块出现都会导致此值为false。
        /// </summary>
        private bool IsSemiAutoNumEnabled
        {
            get
            {
                if (trySemiAutoNum == false) return false;
                if (this.basePanel == null) return false;
                if (this.basePanel.Orientation == Orientation.Horizontal) return false;

                foreach (UIElement ue in this.basePanel.Children)
                {
                    Expressions.BaseText bt = ue as Expressions.BaseText;
                    if (bt == null) continue;

                    if (bt.IsHeaderText || bt.Indent > 0) return false;
                }

                return true;
            }
        }

        /// <summary>
        /// 此方法只应由Subpanel调用。因此不能用于Build SubPanel。
        /// </summary>
        /// <param name="node"></param>
        /// <param name="rootPanel"></param>
        /// <param name="editor"></param>
        /// <returns></returns>
        public static Expression BuildExpression(XmlNode node,
            SubPanel rootPanel, SubPanel parentPanel, Editor editor)
        {
            String typeString = TypeOfExpression.UnKnow.ToString();

            if (node != null)
            {
                typeString = node.GetAttributeString("Type");
            }

            Expression ex;

            switch (typeString)
            {
                case "Arrow":
                    {
                        ex = new Arrow(rootPanel, parentPanel, editor); break;
                    }
                case "Brace":
                    {
                        ex = new Brace(rootPanel, parentPanel, editor); break;
                    }
                case "BaseText":
                    {
                        ex = new BaseText(rootPanel, parentPanel, editor); break;
                    }
                case "Bracket":
                    {
                        ex = new Bracket(rootPanel, parentPanel, editor); break;
                    }
                case "Expander":
                    {
                        ex = new Expander(rootPanel, parentPanel, editor); break;
                    }
                case "Grid":
                    {
                        ex = new Grid(rootPanel, parentPanel, editor); break;
                    }
                case "PictureBox":
                    {
                        ex = new PictureBox(rootPanel, parentPanel, editor); break;
                    }
                case "Triangle":
                    {
                        ex = new Triangle(rootPanel, parentPanel, editor); break;
                    }
                case "LogicCross":
                    {
                        ex = new LogicCross(rootPanel, parentPanel, editor); break;
                    }
                case "LogicGenuspecies":
                    {
                        ex = new LogicGenuspecies(rootPanel, parentPanel, editor); break;
                    }
                case "LogicContradiction":
                    {
                        ex = new LogicContradiction(rootPanel, parentPanel, editor); break;
                    }
                case "MarkText":
                    {
                        ex = new MarkText(rootPanel, parentPanel, editor); break;
                    }
                case "RichText":
                    {
                        ex = new RichText(rootPanel, parentPanel, editor); break;
                    }
                case "Row":
                    {
                        ex = new Row(rootPanel, parentPanel, editor); break;
                    }
                case "SubPanel": return null;//此方法不能用于生成子面板（SubPanel）实例。
                case "GridPanel": return null;//此方法不能用于生成网格面板实例。
                case "Tree":
                    {
                        ex = new Tree(rootPanel, parentPanel, editor); break;
                    }
                // TODO 如果有新公式类型，需要在此处添加。
                default:
                    {
                        ex = new UnKnow(rootPanel, parentPanel, editor); break;
                    }
            }

            ex.XmlData = node;// 这一赋值过程会调用公式的BuildChildren方法以生成公式内部结构。
            return ex;
        }

        public void RefreshAutoNumbersOfBaseText()
        {
            if (this.basePanel == null) return;
            if (this.basePanel.Children.Count <= 0) return;
            if (this.Direction == Orientation.Horizontal)
            {
                for (int i = 0; i < this.basePanel.Children.Count; i++)
                {
                    //只取Indent的[0,3]级，分别对应[lv1Num,lv4Num]
                    Expressions.Expression ex = this.basePanel.Children[i] as Expressions.Expression;
                    if (ex is Expressions.BaseText == false) continue;

                    Expressions.BaseText bt = ex as Expressions.BaseText;
                    bt.AutoNum = 0; bt.SemiAutoNum = 0;
                }
                return;
            }

            if (IsSemiAutoNumEnabled)//如果只有正文文本块，且左缩进都为０。
            {
                for (int i = 1; i <= this.basePanel.Children.Count; i++)
                {
                    Expressions.BaseText bt = this.basePanel.Children[i - 1] as Expressions.BaseText;
                    if (bt != null)
                    {
                        bt.AutoNum = 0;
                        bt.SemiAutoNum = i;
                    }
                }
            }
            else//全自动编号，这是默认方式。
            {
                int lv1Num = 1, lv2Num = 1, lv3Num = 1, lv4Num = 1;

                for (int i = 0; i < this.basePanel.Children.Count; i++)
                {
                    //只取Indent的[0,3]级，分别对应[lv1Num,lv4Num]
                    Expressions.BaseText bt = this.basePanel.Children[i] as Expressions.BaseText;
                    if (bt == null) continue;

                    bt.SemiAutoNum = 0;//非半自动编号。

                    if ((bt.Align != Alignment.LeftOrTop &&
                        bt.Align != Alignment.Default) ||//垂直子面板中的公式默认对齐是左齐
                        bt.FontSizeLevel < 1 || bt.FontSizeLevel > 4)
                    {
                        //如果是顶级标题或顶级副标题。
                        if (bt.FontSizeLevel == 5 || bt.FontSizeLevel == 6)
                        {
                            lv1Num = 1; lv2Num = 1; lv3Num = 1; lv4Num = 1;
                        }

                        bt.AutoNum = 0;
                        continue;
                    }

                    switch (bt.Indent)
                    {
                        case 0:
                            {
                                bt.AutoNum = lv1Num;
                                lv1Num++; lv2Num = 1; lv3Num = 1; lv4Num = 1;
                                break;
                            }
                        case 1:
                            {
                                bt.AutoNum = lv2Num;
                                lv2Num++; lv3Num = 1; lv4Num = 1;
                                break;
                            }
                        case 2:
                            {
                                bt.AutoNum = lv3Num;
                                lv3Num++; lv4Num = 1;
                                break;
                            }
                        case 3:
                            {
                                bt.AutoNum = lv4Num;
                                lv4Num++;
                                break;
                            }
                        default:
                            {
                                bt.AutoNum = 0;//缩进级别过大时，取消自动编号。
                                break;
                            }
                    }

                    bt.RefreshTreeLine();
                }
            }
        }

        public override Expression.Alignment Align
        {
            get
            {
                return base.Align;
            }
            set
            {
                base.Align = value;
                UpdateAlignment();
            }
        }

        public override void UpdateAlignment()
        {
            //判断各子级公式是否“默认对齐”。
            foreach (Expressions.Expression ex in this.basePanel.Children)
            {
                ex.UpdateAlignment();
            }
        }
        
        public override void SetProperty(string propertyName, string value)
        {
            base.SetProperty(propertyName, value);

            switch (propertyName)
            {
                //    case "Indent"://SubPanel无所谓缩进的。
                //        {
                //            this.Indent = int.Parse(value);
                //            break;
                //        }
                case "Direction":
                    {
                        switch (value)
                        {
                            case "Horizontal":
                                {
                                    this.Direction = Orientation.Horizontal;
                                    break;
                                }
                            default:
                                {
                                    this.Direction = Orientation.Vertical;
                                    break;
                                }
                        }
                        break;
                    }
                case "TrySemiAutoNum":
                    {
                        this.TrySemiAutoNum = bool.Parse(value);
                        break;
                    }
            }
        }

        /// <summary>
        /// 此方法是递归方法。
        /// </summary>
        /// <param name="panel">此方法内部会遍历panel中所有公式，如果是标题文本块，就刷新它的树型线，
        /// 否则就看是否子面板，如果是，递归调用此方法。</param>
        public static void RefreshHeaderTextTreeLines(SubPanel panel)
        {
            if (panel == null || panel.BasePanel == null ||
                panel.BasePanel.Children.Count <= 0) return;

            foreach (UIElement ue in panel.BasePanel.Children)
            {
                Expressions.Expression ex = ue as Expressions.Expression;
                if (ex == null) continue;

                Expressions.BaseText bt = ue as Expressions.BaseText;
                if (bt == null)//非文本块。
                {
                    Expressions.SubPanel subPanel = ue as Expressions.SubPanel;
                    if (subPanel == null)
                    {
                        if (ex.SubPanels != null && ex.SubPanels.Count > 0)
                        {
                            foreach (SubPanel sp in ex.SubPanels)
                            {
                                RefreshHeaderTextTreeLines(sp);
                            }
                        }
                    }
                    else
                    {
                        RefreshHeaderTextTreeLines(subPanel);
                    }
                }
                else//文本块。
                {
                    if (bt.ShowTreeLine)
                    {
                        bt.InvalidateArrange();
                        bt.UpdateLayout();
                        bt.RefreshTreeLine();
                    }
                    continue;
                }
            }
        }

        internal void RefreshTreeLinesOfHeaderText()
        {
            if (basePanel == null) return;

            foreach (UIElement ue in basePanel.Children)
            {
                Expressions.BaseText bt = ue as Expressions.BaseText;
                if (bt != null)
                {
                    if (bt.ShowTreeLine)
                    {
                        bt.InvalidateArrange();
                        bt.UpdateLayout();
                        bt.RefreshTreeLine();
                    }
                }
            }
        }
    }
}
